package com.atguigu.gulimaill.cart.service.impl;

import com.atguigu.common.constant.CartConstant;
import com.atguigu.common.utils.R;
import com.atguigu.gulimaill.cart.feign.ProductFeifnService;
import com.atguigu.gulimaill.cart.interceptor.CartInterceptor;
import com.atguigu.gulimaill.cart.service.CartService;
import com.atguigu.gulimaill.cart.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CartServiceImpl implements CartService {
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    ProductFeifnService productFeifnService;
    @Autowired
    ThreadPoolExecutor executor;


    @Override
    public CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> extracted = extracted();
        CartItemVo cartItemVo = new CartItemVo();
        CompletableFuture<Void> getSkuInfo = CompletableFuture.runAsync(() -> {
            R info = productFeifnService.info(skuId);
            SkuInfoEntityVo skuInfo = null;
            if (info.getCode() == 0) {
                skuInfo = R.toPoJo(info.get("skuInfo"), SkuInfoEntityVo.class);
            }
            log.debug("商品信息:{}", skuInfo);
            cartItemVo.setCheck(true);
            cartItemVo.setCount(num);
            if (skuInfo != null) {
                cartItemVo.setImage(skuInfo.getSkuDefaultImg());
            }
            cartItemVo.setPrice(skuInfo.getPrice());
            cartItemVo.setSkuId(skuId);
            cartItemVo.setTitle(skuInfo.getSkuTitle());
        }, executor);

        CompletableFuture<Void> getAttr = CompletableFuture.runAsync(() -> {
            R skuSaleAttrValue = productFeifnService.getSkuSaleAttrValue(skuId);
            if (skuSaleAttrValue.getCode() == 0) {
                List<SkuSaleAttrValueEntityVo> data = R.toListPoJo(skuSaleAttrValue.get("data"), SkuSaleAttrValueEntityVo.class);
                List<String> collect = data.stream().map(item -> item.getAttrName() + ":" + item.getAttrValue()).collect(Collectors.toList());
                cartItemVo.setSkuAttr(collect);
            }
        }, executor);

        CompletableFuture.allOf(getSkuInfo, getAttr).get();
        CartItemVo old = (CartItemVo) extracted.get(skuId.toString());
        if (old != null) {
            cartItemVo.setCount(old.getCount() + num);
        }
        extracted.put(skuId.toString(), cartItemVo);
        log.debug("添加购物车成功:{}", cartItemVo);
        return cartItemVo;
    }

    @Override
    public CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> extracted = extracted();
        Object o = extracted.get(skuId.toString());
        return (CartItemVo) o;
    }

    @Override
    public CartVo getCart() {
        CartVo cartVo = new CartVo();
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            Map<Object, Object> byUserId = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserId()).entries();
            Map<Object, Object> byUserKey = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserKey()).entries();
            if (byUserId == null) {
                byUserId = new HashMap<Object, Object>();
            }
            if (byUserKey == null) {
                byUserKey = new HashMap<Object, Object>();
            }

            for (Object entry : byUserKey.keySet()) {
                CartItemVo byKey = (CartItemVo) byUserKey.get(entry);
                if (byUserId.containsKey(entry)) {
                    //合并
                    CartItemVo byId = (CartItemVo) byUserId.get(entry);
                    byKey.setCount(byId.getCount() + byKey.getCount());

                    byUserId.put(entry, byKey);
                } else {
                    byUserId.put(entry, byKey);
                }
            }
            cartVo.setCartItems(byUserId.values().stream().map(item -> (CartItemVo) item).collect(Collectors.toList()));
            redisTemplate.delete(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserId()).putAll(byUserId);
            //删除
            return cartVo;
        } else {
            List<Object> values = extracted().values();
            if (values != null) {
                List<CartItemVo> collect = values.stream().map(item -> (CartItemVo) item).collect(Collectors.toList());
                cartVo.setCartItems(collect);
            }
            return cartVo;
        }

    }

    @Override
    public void checked(Long skuId, boolean checked) {
        CartItemVo o = (CartItemVo) extracted().get(skuId.toString());
        if (o != null) {
            o.setCheck(checked);
            extracted().put(skuId.toString(), o);
        }
    }

    @Override
    public void countItem(Long skuId, Integer num) {
        CartItemVo o = (CartItemVo) extracted().get(skuId.toString());
        log.debug("修改购物车数量:{}", num);
        if (o != null) {
            o.setCount(num);
            extracted().put(skuId.toString(), o);
        }
    }

    @Override
    public void delItem(Long skuId) {
        extracted().delete(skuId.toString());
    }

    @Override
    public List<CartItemVo> getCurrentUserCartItems() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            List<Object> values = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserId()).values();
            if (values != null) {
                return values.stream()
                        .map(item -> {
                            CartItemVo cartItemVo = (CartItemVo) item;
                            R price = productFeifnService.price(cartItemVo.getSkuId());
                            if (price.getCode() == 0) {
                                cartItemVo.setPrice(new BigDecimal(price.get("data").toString()));
                            } else {
                                throw new RuntimeException("远程调用失败");
                            }
                            cartItemVo.setTotalPrice(cartItemVo.getPrice().multiply(new BigDecimal(cartItemVo.getCount())));
                            return cartItemVo;
                        })
                        .filter(CartItemVo::getCheck)
                        .collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }

    private BoundHashOperations<String, Object, Object> extracted() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String key = CartConstant.CART_PREFIX;
        if (userInfoTo.getUserId() != null) {
            key += userInfoTo.getUserId().toString();
        } else {
            key += userInfoTo.getUserKey();
        }
        log.debug("key:{}", key);
        return redisTemplate.boundHashOps(key);
    }
}
